package com.xbai.juc;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁：可重复可递归调用的锁，在外层使用锁之后，在内层仍然可以使用，并且不发生死锁，这样的锁就叫做可重入锁。
 * <p>
 * 在一个 synchronized 修饰的方法或代码块的内部，调用本类的其它 synchronized 修改的方法或代码块时，是永远可以得到锁的
 *
 * @author xbai
 * @Date 2021/5/13
 */
public class ReEnterLockDemo {

    static Lock lock = new ReentrantLock();

    public static void main(String[] args) {

        new Thread(() -> {
            try {
                lock.lock();
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "\t" + "------ 外层调用");
                try {
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + "\t" + "------ 内层调用");
                } finally {
                    lock.unlock();
                }
            } finally {
                // 这里故意注释，实现加锁次数和释放锁次数不一样
                // 由于加锁次数和释放锁次数不一样，第二个线程始终无法获取到锁，导致一直在等待
                // 正常情况下，加锁几次就需要解锁几次
//                lock.unlock();
                lock.unlock();
            }
        }, "t1").start();

        new Thread(() -> {
            try {
                lock.lock();
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "\t" + "------ 外层调用");
                try {
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + "\t" + "------ 内层调用");
                } finally {
                    lock.unlock();
                }
            } finally {
                lock.unlock();
                lock.unlock();
            }
        }, "t2").start();
    }

   /* static Object objectLockA = new Object();

    public static void m1() {
        synchronized (objectLockA) {
            System.out.println(Thread.currentThread().getName() + "\t" + "------ 外层调用");
            synchronized (objectLockA) {
                System.out.println(Thread.currentThread().getName() + "\t" + "------ 中层调用");
                synchronized (objectLockA) {
                    System.out.println(Thread.currentThread().getName() + "\t" + "------ 内层调用");
                }
            }

        }
    }*/


    /*public synchronized void m1() {
        System.out.println(Thread.currentThread().getName() + "\t" + "------ 外层调用");
        m2();
    }

    public synchronized void m2() {
        System.out.println(Thread.currentThread().getName() + "\t" + "------ 中层调用");
        m3();
    }

    public synchronized void m3() {
        System.out.println(Thread.currentThread().getName() + "\t" + "------ 内层调用");
    }

    public static void main(String[] args) {
        new ReEnterLockDemo().m1();
    }*/
}
